package com.server.core;

import gnu.cajo.utils.extra.TransparentItemProxy;

import java.io.*;
import org.w3c.dom.Element;

import com.server.runtime.simulationImpl;

import combat.protocol.data.DoublePoint;
import combat.protocol.interfaces.SimulationInt;
import combat.protocol.interfaces.TeamInt;

//input
public class JConsole 
{
	public static SimulationInt simulation;
	
	static final String HELP = 			"help";
	static final String LIST = 			"list";
	
	static final String SERVER =		"server";
	static final String START =			"start";
	static final String STOP =			"stop";
	static final String RESTART = 		"restart";
	static final String EXIT = 			"exit";
	
	static final String GAME = 			"game";
	static final String SHUTDOWN = 		"shutdown";
	static final String PAUSE = 		"pause";
	static final String CONTINUE = 		"continue";
	static final String G_SPEED = 		"speed";
	static final String S_TIME = 		"simtime";
	
	static final String PHYSICALOBJECT = "po";
	static final String VEHICLE =		 "vehicle";
	
	static final String SET = 			"set";
	static final String NAME = 			"name";
	static final String POSITION = 		"pos";
	static final String ALTITUDE = 		"alt";
	static final String DIRECTION = 	"dir";
	static final String SPEED = 		"speed";
	static final String SHAPE = 		"shape";
	static final String MAXSPEED = 		"maxspeed";
	static final String MAXTURNSPEED =	"maxturnspeed";
	static final String HEALTH = 		"health";
	static final String LOCKED = 		"locked";
	static final String INFO = 			"info"; 
	static final String TEAM = 			"team";
	
	static final String ORDER = 		"order";
	static final String MOVE = 			"move";
	static final String CANCEL = 		"cancel";
	
	static final String SCENARIO =		"scenario";
	static final String LOAD = 			"load";
	static final String LOADFILE = 		"loadfile";
	static final String LOADTEAMS =		"loadteams";
	static final String LOADPO = 		"loadpo";
	
	static Runnable r1 = new Runnable() {
		public void run() {
			while (true) {
				  //  prompt the user to enter their name
			      System.out.print(">");

			      //  open up standard input
			      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			      String input = null;

			      try {
					  input = br.readLine();
				  } catch (IOException ioe) {
					  System.out.println("ERROR: IO Reading error!");
				      System.exit(1);
				  }
				  String[] items = input.split(" ");
				  
				  basicCommands(items);
			}
		     
		}
	};
	
	public static void startConsole() {
		try {
			simulation = (SimulationInt) TransparentItemProxy.getItem(
					"//"+ Config.cajoHost +":"+ Config.cajoPort +"/Simulation", new Class[] { SimulationInt.class });
		} catch (Exception e) {
			System.out.println("ERROR: Could not connect.");
		}
		
		Thread thr1 = new Thread(r1);
		thr1.start();
		System.out.println("CONSOLE: type \""+HELP+"\" for a console keyword overview.\n");
		
	}
	
	public static void basicCommands(String[] items) {
		if(items.length >= 1) {
			if(items[0].equals(HELP)) {
				System.out.println(	"-------Function overview-------\n" 	+
									"help:				"	+ HELP + "\n" +
									"print list:	\t	" 	+ LIST + " ["+PHYSICALOBJECT+"]/["+VEHICLE+"]/["+TEAM+"]\n" +
									"server control:\t\t\t" + SERVER + "["+START+"]/["+STOP+"]/["+EXIT+"]\n" +
									"game control:\t\t\t"	+ GAME + "["+SHUTDOWN+"] / ["+PAUSE+"] / ["+CONTINUE+"] / ["+S_TIME+"] / (["+G_SPEED+"] + value)\n" +
									"set properties:\t\t\t" + SET  + " ["+PHYSICALOBJECT+"]/["+VEHICLE+"]/["+ORDER+"]\n" +
									"load scenario:\t\t\t" + SCENARIO + " ["+LOAD+"]/["+LOADFILE+"]/["+LOADTEAMS+"]/["+LOADPO+"]\n" +
									"----End of function overview----");
			
			} else if (items[0].equals(LIST)) {	  	
				if(items.length >= 2) {
					if(items[1].equals(PHYSICALOBJECT)) {
						simulationImpl.printPOList();
					} else if(items[1].equals(VEHICLE)) {				
						simulationImpl.printVehiclesListByTeams();
					} else if(items[1].equals(TEAM)){
						simulationImpl.printTeams();
					}
					else {
						System.out.println("ERROR: Unknown command!");
					}
				} else {
					System.out.println(	LIST + " ["+PHYSICALOBJECT+"] / ["+VEHICLE+"]\n");
				}
			} else if (items[0].equals(SERVER)) { 
				if (items.length >= 2) {
					if(items[1].equals(START)){
						try {
							Server.startServer();
						} catch (Exception e) {
							System.out.println("Couldn't start server");
						}
					} else if(items[1].equals(STOP)) {
						try {
							Server.shutdownServer();
						} catch (Exception e) {
							System.out.println("Couldn't stop server");
						}
					} else if(items[1].equals(RESTART)) {
						try {
							Server.restartServer();
						} catch (Exception e) {
							System.out.println("An error occured while restarting the server");
						}
					} else if(items[1].equals(EXIT)){
						System.exit(1);
					} else {
						System.out.println(	SERVER + " ["+START+"] / ["+STOP+"] / ["+EXIT+"]\n");
					}
				}
			} else if (items[0].equals(GAME)) {	  	
				if(items.length >= 2) {
					game(items);
				} else {
					System.out.println(	GAME + " ["+SHUTDOWN+"] / ["+PAUSE+"] / ["+CONTINUE+"] / (["+G_SPEED+"] + value)\n");
				}
			} else if(items[0].equals(SET)) {
				if(items.length >= 3) {
					if(items[1].equals(PHYSICALOBJECT)) {
						//setPhysicalObjects(items);
					} else if(items[1].equals(VEHICLE)) {
						setVehicles(items);
					} else if(items[1].equals(ORDER))	{
						setAllOrder(items);
					} else {
						noValidMember(items[1]);
					}
					
				} else {
					System.out.println(	SET +	"\n" +
												"\"\t ["+	PHYSICALOBJECT	+"]\t            + [#] + ["+NAME+"]/["+POSITION+"]/["+ALTITUDE+"]/["+DIRECTION+"]/["+SPEED+"]/["+SHAPE+"]/["+MAXSPEED+"]/["+MAXTURNSPEED+"] + new value(s)\n" +
												"\"\t ["+	VEHICLE			+"]\t + teamname + [#] + ["+NAME+"]/["+POSITION+"]/["+ALTITUDE+"]/["+DIRECTION+"]/["+SPEED+"]/["+SHAPE+"]/["+MAXSPEED+"]/["+MAXTURNSPEED+"]/["+HEALTH+"]/["+LOCKED+"]/["+INFO+"]/(["+TEAM+"] + teamname)/s["+ORDER+"] + (["+MOVE+"] + position)/["+CANCEL+"])\n" +
												"\"\t ["+	ORDER			+"] + (["+MOVE+"] + position)/["+CANCEL+"]" 
										);				
				}
			} else if(items[0].equals(SCENARIO)) { 
				if(items.length >= 2){
					Element loadFile = null;
					if(items.length >= 3 && items[2].length() > 0 && !items[1].equals(LOAD) && !items[1].equals(LOADFILE)){
						try {
							loadFile = DocLoader.loadFile(items[2]);
						} catch (Exception e) {
							System.out.println("The XML file couldn't be loaded");
						}
					}
					
					if(items[1].equals(LOAD)){
						try {
							//Load all data in once
							loadFile = DocLoader.loadFile(items[2]);
							//Load teams
							DocLoader.loadTeams(loadFile);
							//Load Vehicles
							DocLoader.loadVehicles(loadFile);
						} catch(Exception e){
							System.out.println("ERROR: Something went wrong during init of scenario");
						}
					} else if(items[1].equals(LOADFILE)) { 
						try {
							DocLoader.loadFile(items[2]);
						} catch (Exception e){
							System.out.println("ERROR: Could not load XML file");
						}
					} else if(items[1].equals(LOADTEAMS)) {
						if(loadFile != null) {
							System.out.println("ERROR: No XML file loaded"); 
						} else {
							try {
								DocLoader.loadTeams(loadFile);
							} catch(Exception e){
								System.out.println("ERROR: Could not load the teams");
							}
						}
					} else if(items[1].equals(LOADPO)){
						if(loadFile != null) { 
							System.out.println("ERROR: No XML file loaded"); 
						} else {
							try {
								DocLoader.loadVehicles(loadFile);
							} catch (Exception e1) {
								System.out.println("ERROR: Could not load vehicles");
							}
						}
					}
				} else {
					System.out.println( SCENARIO + "\n" +
													"\t["+LOAD+"] [filename] \n" +
													"\t["+LOADFILE+"] [filename \n" +
													"\t["+LOADTEAMS+"] \n" +
													"\t["+LOADPO+"]\n");
				}
			} else {
				noValidMember(items[0]);
			}
		}	
	}
	
	//game
	private static void game(String[] items)
	{
		if (items[1].equals(SHUTDOWN))
		{	
			BufferedReader br_temp = new BufferedReader(new InputStreamReader(System.in));
			String confirm = "";	
			System.out.print("Are you sure? (y)es/(n)o \n>");
			try {
				confirm = br_temp.readLine();
			} catch (IOException ioe) {
				  System.out.println("ERROR: IO Reading error!");
			      System.exit(1);
			}
			
			if(confirm.equals("y")||confirm.equals("yes")||confirm.equals("Y"))
			{
				try
				{
					Server.shutdownServer();
				}
				catch(Exception e1)
				{
					System.out.println("ERROR: The server is still online. Please turn it offline.");
					//Check if debug mode is turned on
					if(Config.debugMode){
						System.out.println(e1);
						e1.printStackTrace();
					}
				}
			}			
		}
		else if (items[1].equals(PAUSE)) {
			simulation.pauseSimulation();
		} else if (items[1].equals(CONTINUE)) {
			simulation.setSimSpeed(1.0);
		} else if (items[1].equals(G_SPEED)) {
			if(items.length < 3){
				System.out.println("UPDATE: Speed multiplier: " + simulation.getSimSpeed());
				return;
			}
			if (!isParsableToDouble(items[2])){
				faultValue(items[2]);//error message
				return;
			}			
			simulation.setSimSpeed(Double.parseDouble(items[2]));
		} else {
			noValidMember(items[1]);
		}
	}
	
	
	/*set
	private static void setPhysicalObjects(String[] items)
	{
		String sentence = "";
		Double pos1 = 0.0;
		Double pos2 = 0.0;
		int i1 = 0;
		if(!isParsableToInt(items[2]) || simulationImpl.physicalObjects.size() < Integer.parseInt(items[2])){
			noValidMember(items[2]);//error message, not parseable or in range
			return;
		}
			
		if(items.length < 5){//check for at least one input value
			noValue();
			return;
		}
		
		if(items[3].equals(NAME)) {
			for(int i = 4; i<items.length; i++)
				sentence = sentence +  items[i] + " ";
			simulationImpl.getReference().physicalObjects.get(Integer.parseInt(items[2])).setName(sentence);
		}
		else if(items[3].equals(POSITION)) {
			if(items.length < 6) {
				return;
			}
			if (!isParsableToDouble(items[4]) || !isParsableToDouble(items[5])){
				faultValue((items[4] + " " + items[5]));//error message
				return;
			}
			pos1 = Double.parseDouble(items[4]);
			pos2 = Double.parseDouble(items[5]);
			simulationImpl.physicalObjects.get(Integer.parseInt(items[2])).setPosition(new DoublePoint(pos1, pos2));
		} else if(items[3].equals(ALTITUDE)) {
			if (!isParsableToInt(items[4])){
				faultValue(items[4]);//error message
				return;
			}				
			i1 = Integer.parseInt(items[4]);
			simulationImpl.physicalObjects.get(Integer.parseInt(items[2])).setAltitude(i1);
		} else if(items[3].equals(DIRECTION))	 {
			if (!isParsableToDouble(items[4])){
				faultValue(items[4]);//error message
				return;
			}
			pos1 = Double.parseDouble(items[4]);
			simulationImpl.physicalObjects.get(Integer.parseInt(items[2])).setDirection(pos1);
		} else if(items[3].equals(SPEED)) {
			if (!isParsableToDouble(items[4])){
				faultValue(items[4]);//error message			
				return;
			}
			pos1 = Double.parseDouble(items[4]);
			simulationImpl.physicalObjects.get(Integer.parseInt(items[2])).setSpeed(pos1);
		} else {
			noValidMember(items[3]);
		}
		
	}*/
	
	private static void setVehicles(String[] items)
	{
		String sentence = "";
		Double pos1 = 0.0;
		Double pos2 = 0.0;
		int i1 = 0;
		TeamInt team = null;
		
		for(int i = 0; i < simulationImpl.getReference().getTeams().size(); i++) {
			if(items[2].equals(simulationImpl.getReference().getTeams().get(i).getTeamName())) {
				team = simulationImpl.getReference().getTeams().get(i);
				break;
			}
		}
		if(team == null){
			noTeam();
			return;
		}
				
		if(!isParsableToInt(items[3]) || simulationImpl.getReference().getTeams().size() < Integer.parseInt(items[3])){
			noValidMember(items[3]);//error message, not parseable or in range
			return;
		}
		
		if(items.length < 6){//check for at least one input value
			noValue();
			return;
		}
		
		if(items[4].equals(NAME)) {
			for(int i = 5; i<items.length; i++)
				sentence = sentence +  items[i] + " ";
			team.getVehicles().get(Integer.parseInt(items[3])).setName(sentence);
		} else if(items[4].equals(POSITION)) {
			if(items.length < 7) {
				return;
			}
			if (!isParsableToDouble(items[5]) || !isParsableToDouble(items[6])){
				faultValue((items[5] + " " + items[6]));// error message
				return;
			}
			pos1 = Double.parseDouble(items[5]);
			pos2 = Double.parseDouble(items[6]);
			team.getVehicles().get(Integer.parseInt(items[3])).setPosition(new DoublePoint(pos1, pos2));
		} else if(items[4].equals(ALTITUDE)) {
			if (!isParsableToInt(items[5])){
				faultValue(items[5]);//error message
				return;
			}			
			i1 = Integer.parseInt(items[5]);
			team.getVehicles().get(Integer.parseInt(items[3])).setAltitude(i1);
		} else if(items[4].equals(DIRECTION)) {
			if (!isParsableToDouble(items[5])){
				faultValue(items[5]);//error message
				return;
			}			
			pos1 = Double.parseDouble(items[5]);
			team.getVehicles().get(Integer.parseInt(items[3])).setDirection(pos1);
		} else if(items[4].equals(SPEED)) {
			if (!isParsableToDouble(items[5])){
				faultValue(items[5]);//error message
				return;
			}				
			pos1 = Double.parseDouble(items[5]);
			team.getVehicles().get(Integer.parseInt(items[3])).setSpeed(pos1);
		}
		else if(items[4].equals(HEALTH))										//HEALTH
		{
			if (!isParsableToDouble(items[5])){
				faultValue(items[5]);//error message
				return;
			}
			team.getVehicles().get(Integer.parseInt(items[3])).setHealth(Integer.parseInt(items[5]));
		} else if(items[4].equals(LOCKED)) {
			if (!isParsableToInt(items[5])){
				faultValue(items[5]);//error message
				return;
			}
			i1 = Integer.parseInt(items[5]);
			if(i1 == 1)
				team.getVehicles().get(Integer.parseInt(items[3])).lock();
			else if(i1 == 0)
				team.getVehicles().get(Integer.parseInt(items[3])).unlock();
		} else if(items[4].equals(TEAM))	 {
			//TODO: the team has to be changed
			//team.getVehicles().get(Integer.parseInt(items[3])).changeTeam(items[5]);
		} else if(items[4].equals(ORDER))	 {
			if(items[5].equals(MOVE)) {		
				if(items.length < 8) {
					noValue();
					return;
				}
					
				if (!isParsableToDouble(items[6]) || !isParsableToDouble(items[7])){
					faultValue(items[6] + " " + items[7]);//error message
					return;
				}				
				pos1 = Double.parseDouble(items[6]);
				pos2 = Double.parseDouble(items[7]);
				team.getVehicles().get(Integer.parseInt(items[3])).orderMove(0, new DoublePoint(pos1, pos2), (int)team.getVehicles().get(Integer.parseInt(items[3])).getSpeed());
				System.out.println("UPDATE: Move order added ("+items[6]+", "+items[7]+").");
			} else if(items[5].equals(CANCEL)) {					
				if(team.getVehicles().get(Integer.parseInt(items[3])).getOrders()!= null && team.getVehicles().get(Integer.parseInt(items[3])).getOrders().size()>0) {
					team.getVehicles().get(Integer.parseInt(items[3])).getOrders().remove(team.getVehicles().get(Integer.parseInt(items[3])).getOrders().get(0));
					System.out.println("UPDATE: Order canceled.");
				} else {
					System.out.println("ERROR: No orders found.");
				}				
			}
		} else {
			noValidMember(items[4]);
		}
	}
	
	public static void setAllOrder(String[] items)
	{
		double pos1 = 0.0;
		double pos2 = 0.0;
		
		if(items[2].equals(MOVE)) {			
			if(items.length < 5) {
				noValue();
				return;
			}
			
			if (!isParsableToDouble(items[3]) || !isParsableToDouble(items[4])){
				faultValue(items[3] + " " + items[4]);//error message
				return;
			}				
			pos1 = Double.parseDouble(items[3]);
			pos2 = Double.parseDouble(items[4]);
			for(int i = 0; i < simulationImpl.getReference().getTeams().size(); i++) {
				for(int j = 0; j <simulationImpl.getReference().getTeams().get(i).getVehicles().size(); j++) {
					simulationImpl.getReference().getTeams().get(i).getVehicles().get(j).orderMove(0, new DoublePoint(pos1, pos2), (int)simulationImpl.getReference().getTeams().get(i).getVehicles().get(j).getSpeed());
				}
			}
			System.out.println("UPDATE: Move orders added ("+items[3]+", "+items[4]+").");
		} else if(items[2].equals(CANCEL)) {	
			for(int i = 0; i < simulationImpl.getReference().getTeams().size(); i++) {
				for(int j = 0; j <simulationImpl.getReference().getTeams().get(i).getVehicles().size(); j++) {					
					if(simulationImpl.getReference().getTeams().get(i).getVehicles().get(j).getOrders()!= null && simulationImpl.getReference().getTeams().get(i).getVehicles().get(j).getOrders().size()>0) {	
						simulationImpl.getReference().getTeams().get(i).getVehicles().get(j).getOrders().remove(simulationImpl.getReference().getTeams().get(i).getVehicles().get(j));
					}
				}
			}	
			System.out.println("UPDATE: Orders canceled.");
		}
	}
	
	public static void noTeam() {
		System.out.println("ERROR: No valid team selected!");		
	}
	
	public static void noValue() {
		System.out.println("ERROR: No input value!");		
	}
	
	public static void noValidMember(String x) {
		System.out.println("ERROR: '"+x+"', is not a valid member!");		
	}
	
	public static void faultValue(int x) {
		System.out.println("ERROR: Unknown value: " + x);		
	}
	
	public static void faultValue(double x) {
		System.out.println("ERROR: Unknown value: " + x);		
	}
	
	public static void faultValue(String x) {
		System.out.println("ERROR: Unknown value: " + x);		
	}
	
	public static boolean isParsableToInt(String i) {
		try{
			Integer.parseInt(i);
			return true;
		}
		catch(NumberFormatException nfe){
			return false;
		}
	}	
	public static boolean isParsableToDouble(String i) {
		try{
			Double.parseDouble(i);
			return true;
		}
		catch(NumberFormatException nfe){
			return false;
		}
	}
}
